﻿using System;
using System.Diagnostics;
using System.Xml;

using pt=System.UInt32;

namespace RDLC
{
   public abstract class RDLStyle
   {
      public enum RDLColor
      {
         Black,
         Blue,         
         Red,
         Yellow,
         Green, 
         Default = Black
      };

      public enum RDLBackgroundGradient
      {
         None,
         LeftRight,
         TopBottom,
         Center,
         DiagonalLeft,
         DiagonalRight,
         HorizontalCenter,
         VerticalCenter,
         Default = None
      };

      public enum RDLFontStyle
      {
         Normal,
         Italic,
         Default = Normal
      };

      public enum RDLFontFamily
      {
         Arial,
         Default = Arial
      };

      public enum RDLFontWeight
      {
         Normal,
         Lighter,
         Bold,
         Bolder,
         W100 = 100,
         W200 = 200,
         W300 = 300,
         W400 = 400,
         W500 = 500,
         W600 = 600,
         W700 = 700,
         W800 = 800,
         W900 = 900,
         Default = Normal
      };

      public enum RDLTextDecoration
      {                  
         None,
         Underline,
         Overline,
         LineThrough,
         Default = None
      };

      public enum RDLTextAlign
      {
         Left,
         Center,
         Right,
         General,
         Default = Left
      };

      public enum RDLVerticalAlign
      {
         Default,
         Top,
         Middle,
         Bottom
      };

      public enum RDLWritingMode
      {
         Default,
         Lr_tb,
         Tb_rl
      };

      public enum RDLUnicodeBiDi
      {
         Default,
         Normal,
         Embed,
         BiDi_Override
      };

      public enum RDLImageSource
      {
         External,
         Embedded,
         DataBase
      };


      public enum ImageMimeType { bmp, jpg, gif, png, jpe }

      public enum RDLMIMEType
      {
         BMP,
         JPEG,
         GIF,
         PNG,
         X_PNG
      };

      public enum RDLBackgroundRepeat
      {
         Default,
         Repeat,
         NoRepeat,
         RepeatX,
         RepeatY
      };

      public class RDLBorderColor
      {
         public RDLBorderColor(RDLColor? color)
         {
            Default = color;
         }

         public RDLBorderColor(RDLColor? left, RDLColor? right, RDLColor? top, RDLColor? bottom)
         {
            Left = left;
            Right = right;
            Top = top;
            Bottom = bottom;
         }
         
         public void Write(XmlTextWriter writer)
         {
            writer.WriteStartElement("BorderColor");
            if (Default.HasValue)
            {
               writer.WriteElementString("Default", Default.Value.ToString());
            }
            if (Left.HasValue)
            {
               writer.WriteElementString("Left", Right.Value.ToString());
            }
            if(Right.HasValue)
            {
               writer.WriteElementString("Right", Right.Value.ToString());
            }
            if(Top.HasValue)
            {
               writer.WriteElementString("Top", Top.Value.ToString());  
            }
            if(Bottom.HasValue)
            {
               writer.WriteElementString("Bottom", Bottom.Value.ToString());
            }
            writer.WriteEndElement(); // BorderColor 
         }

         public RDLColor? Default
         {
            get { return _Default; }
            set
            {
               if (!_Default.HasValue)
                  _Default = new RDLColor();
               _Default = value;
            }
         }
         private RDLColor? _Default;
         public RDLColor? Left
         {
            get { return _Left; }
            set
            {
               if (!_Left.HasValue)
                  _Left = new RDLColor();
               _Left = value;
            }
         }
         public RDLColor? _Left;
         public RDLColor? Right
         {
            get { return _Right; }
            set
            {
               if (!_Right.HasValue)
                  _Right = new RDLColor();
               _Right = value;
            }
         }
         public RDLColor? _Right;
         public RDLColor? Top
         {
            get { return _Top; }
            set
            {
               if (!_Top.HasValue)
                  _Top = new RDLColor();
               _Top = value;
            }
         }
         public RDLColor? _Top;
         public RDLColor? Bottom
         {
            get { return _Bottom; }
            set
            {
               if (!_Bottom.HasValue)
                  _Bottom = new RDLColor();
               _Bottom = value;
            }
         }
         public RDLColor? _Bottom;
      }

      public class RDLBorderStyle
      {
         public RDLBorderStyle(Style? style)
         {
            Default = style;
         }

         public RDLBorderStyle(Style? left, Style? right, Style? top, Style? bottom)
         {
            Left = left;
            Right = right;
            Top = top;
            Bottom = bottom;
         }

         public enum Style
         {
            None,
            Dotted,
            Dashed,
            Solid,
            Double,
            Groove,
            Ridge,
            Inset,
            WindowInset,
            Outset,
            Default = None
         };

         public void Write(XmlTextWriter writer)
         {
            writer.WriteStartElement("BorderStyle");
            if (Default.HasValue)
            {
               writer.WriteElementString("Default", Default.Value.ToString());
            }
            if (Left.HasValue)
            {
               writer.WriteElementString("Left", Right.Value.ToString());
            }
            if(Right.HasValue)
            {
               writer.WriteElementString("Right", Right.Value.ToString());
            }
            if(Top.HasValue)
            {
               writer.WriteElementString("Top", Top.Value.ToString());  
            }
            if(Bottom.HasValue)
            {
               writer.WriteElementString("Bottom", Bottom.Value.ToString());
            }
            writer.WriteEndElement(); // BorderStyle
         }

         public Style? Default
         {
            get { return _Default; }
            set
            {
               if(!_Default.HasValue)
                  _Default = new Style();
               _Default = value;
            }
         }
         private Style? _Default;
         public Style? Left
         {
            get { return _Left; }
            set
            {
               if (!_Left.HasValue)
                  _Left = new Style();
               _Left = value;
            }
         }
         public Style? _Left;
         public Style? Right
         {
            get { return _Right; }
            set
            {
               if (!_Right.HasValue)
                  _Right = new Style();
               _Right = value;
            }
         }
         public Style? _Right;
         public Style? Top
         {
            get { return _Top; }
            set
            {
               if (!_Top.HasValue)
                  _Top = new Style();
               _Top = value;
            }
         }
         public Style? _Top;
         public Style? Bottom
         {
            get { return _Bottom; }
            set
            {
               if (!_Bottom.HasValue)
                  _Bottom = new Style();
               _Bottom = value;
            }
         }
         public Style? _Bottom;
      }

      public class RDLBorderWidth
      {
         public const pt DefaultValue = 1;

         public RDLBorderWidth(pt? width)
         {
            Default = width;
         }

         public RDLBorderWidth(pt? left, pt? right, pt? top, pt? bottom)
         {
            Left = left;
            Right = right;
            Top = top;
            Bottom = bottom;
         }

         internal static bool IsValidWidth(pt? width)
         {                      
            if(!width.HasValue)
               return true;
            
            bool rtn = (width.Value >= 0.25) && (width.Value <= 20.0);

            Debug.Assert(rtn);
            
            if (!rtn)
            {
               throw new Exception();
            }

            return rtn;
         }

         public void Write(XmlTextWriter writer)
         {
            writer.WriteStartElement("BorderWidth");
            if (Default.HasValue)
               writer.WriteElementString("Default", Default.Value + "pt");

            if (Left.HasValue)
               writer.WriteElementString("Left", Right.Value + "pt");

            if (Right.HasValue)
               writer.WriteElementString("Right", Right.Value + "pt");

            if (Top.HasValue)
               writer.WriteElementString("Top", Top.Value + "pt");

            if (Bottom.HasValue)
               writer.WriteElementString("Bottom", Bottom.Value + "pt");

            writer.WriteEndElement(); // BorderWidth
         }

         public pt? Default
         {
            get { return _Default; }
            set
            {
               if (IsValidWidth(value))
                  _Default = value;
            }
         }
         private pt? _Default;
         public pt? Left
         {
            get { return _Left; }
            set
            {
               if (IsValidWidth(value))
                  _Left = value;
            }
         }
         public pt? _Left;
         public pt? Right
         {
            get { return _Right; }
            set
            {
               if (IsValidWidth(value))
                  _Right = value;
            }
         }
         public pt? _Right;
         public pt? Top
         {
            get { return _Top; }
            set
            {
               if (IsValidWidth(value))
                  _Top = value;
            }
         }
         public pt? _Top;
         public pt? Bottom
         {
            get { return _Bottom; }
            set
            {
               if (IsValidWidth(value))
                  _Bottom = value;
            }
         }
         public pt? _Bottom;
      }
      
      public class RDLPadding
      {
         public const uint DefaultValue = 0;
         
         public RDLPadding(uint? padding)
         {
            Left = padding;
            Right = padding;
            Top = padding;
            Bottom = padding;            
         }

         public RDLPadding(uint? left, uint? right, uint? top, uint? bottom)
         {
            Left = left;
            Right = right;
            Top = top;
            Bottom = bottom;
         }

         public static bool IsValidPadding(uint? padding)
         {
            if(!padding.HasValue)
               return true;

            bool rtn = (padding <= 1000);

            Debug.Assert(rtn);

            if(!rtn)
            {
               throw new Exception("Padding value must be between 0 and 200");
            }

            return rtn;
         }

         public void Write(XmlTextWriter writer)
         {
            if(Left.HasValue)
               writer.WriteElementString("PaddingLeft", Left + "pt");
            if(Right.HasValue)
               writer.WriteElementString("PaddingRight", Right + "pt");
            if(Top.HasValue)
               writer.WriteElementString("PaddingTop", Top + "pt");
            if(Bottom.HasValue)
               writer.WriteElementString("PaddingBottom", Bottom + "pt");
         }

         public uint? Left
         {
            get { return _Left; }
            set
            {
               if (IsValidPadding(value))
               {
                  if (!_Left.HasValue)
                     _Left = new uint();
                  _Left = value;
               }
            }
         }
         public uint? _Left;

         public uint? Right
         {
            get { return _Right; }
            set
            {
               if (IsValidPadding(value))
               {
                  if (!_Right.HasValue)
                     _Right = new uint();
                  _Right = value;
               }
            }
         }
         public uint? _Right;
         public uint? Top
         {
            get { return _Top; }
            set
            {
               if (IsValidPadding(value))
               {
                  if (!_Top.HasValue)
                     _Top = new uint();
                  _Top = value;
               }
            }
         }
         public uint? _Top;
         public uint? Bottom
         {
            get { return _Bottom; }
            set
            {
               if (IsValidPadding(value))
               {
                  if (!_Bottom.HasValue)
                     _Bottom = new uint();
                  _Bottom = value;
               }
            }
         }
         public uint? _Bottom;
      }

      public static bool IsValidLineHeight(uint? lineHeight)
      {
         if(!lineHeight.HasValue)
            return false;

         bool rtn = (lineHeight <= 1000);

         Debug.Assert(rtn);

         if (!rtn)
         {
            throw new Exception("Line height must be between 0 and 200");
         }

         return rtn;
      }      
      public static bool IsValidFontSize(uint fontSize)
      {
         bool rtn = (fontSize > 0 &&  fontSize <= 200);

         Debug.Assert(rtn);

         if(rtn)
         {
            throw new Exception("Font size must be from 1 to 200.");
         }

         return rtn;
      }
      public const uint DefaultFontSize = 10;

      public RDLBorderColor BorderColor;
      public RDLBorderStyle BorderStyle;
      public RDLBorderWidth BorderWidth;

      protected RDLStyle(RDLBorderColor borderColor, RDLBorderStyle borderStyle, RDLBorderWidth borderWidth)
      {
         BorderColor = borderColor;
         BorderStyle = borderStyle;
         BorderWidth = borderWidth;
      }

      protected RDLStyle()
      {

      }

      public void Write(XmlTextWriter writer)
      {
         writer.WriteStartElement("Style");

         if(BorderStyle != null)
            BorderStyle.Write(writer);

         if (BorderColor != null)
            BorderColor.Write(writer);

         if (BorderWidth != null)
            BorderWidth.Write(writer);

         WriteDetails(writer);

         writer.WriteEndElement(); // Style             
      }         
      
      protected abstract void WriteDetails(XmlTextWriter writer);
   }
}
